home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #4 / Amiga Plus CD - 2000 - No. 4.iso / Tools / Dev / Orbit_SRC / hud.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-27  |  31.7 KB  |  1,443 lines

  1. /*
  2.     Amiga port by Oliver Gantert
  3.  
  4.     27.04.2000 - fixed some compiler warnings
  5. */
  6. /*
  7.  
  8. ORBIT, a freeware space combat simulator
  9. Copyright (C) 1999  Steve Belczyk <steve1@genesis.nred.ma.us>
  10.  
  11. This program is free software; you can redistribute it and/or
  12. modify it under the terms of the GNU General Public License
  13. as published by the Free Software Foundation; either version 2
  14. of the License, or (at your option) any later version.
  15.  
  16. This program is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. GNU General Public License for more details.
  20.  
  21. You should have received a copy of the GNU General Public License
  22. along with this program; if not, write to the Free Software
  23. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  24.  
  25. */
  26.  
  27. #include "orbit.h"
  28.  
  29. static GLubyte throt_stipple[] = {
  30.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  31.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  32.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  33.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  34.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  35.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  36.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  37.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  38.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  39.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  40.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  41.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  42.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  43.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  44.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
  45.   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
  46. }
  47. ;
  48.  
  49. void InitHud()
  50. /*
  51.  *  Initialize the HUD
  52.  */
  53. {
  54.   InitRadar();
  55.   MakeRadarCircleList();
  56.  
  57.   /* Figure out throttle coords */
  58.   hud.throt_min[0] = radar.fcenter[0] - 1.4*radar.fradius;
  59.   hud.throt_min[1] = radar.fcenter[1] - 0.9*radar.fradius;
  60.   hud.throt_max[0] = hud.throt_min[0] + 0.2*radar.fradius;
  61.   hud.throt_max[1] = hud.throt_min[1] + 1.8*radar.fradius;
  62.   hud.throt_mid[0] = hud.throt_min[0];
  63.   hud.throt_mid[1] = (hud.throt_min[1] + hud.throt_max[1]) / 2.0;
  64.  
  65.   /* Target name */
  66.   hud.targ_name[0] = radar.fcenter[0] + 2.0*radar.fradius;
  67.   hud.targ_name[1] = radar.fcenter[1] - radar.fradius + 10.0;
  68.  
  69.   /* Target range */
  70.   hud.targ_range[0] = hud.targ_name[0];
  71.   hud.targ_range[1] = hud.targ_name[1] - 10.0;
  72.  
  73.   /* Waypoint */
  74.   hud.waypoint[0] = hud.targ_range[0];
  75.   hud.waypoint[1] = hud.targ_range[1];
  76.  
  77.   /* Weapon name */
  78.   hud.weapon[0] = hud.targ_name[0];
  79.   hud.weapon[1] = radar.fcenter[1] + radar.fradius - 20.0;
  80.  
  81.   /* Velocity */
  82.   hud.vel[0] = radar.fcenter[0] - 3.0 * radar.fradius;
  83.   hud.vel[1] = hud.throt_mid[1] - 5.0;
  84.  
  85.   /* Shields display */
  86.   hud.shields_min[0] = radar.fcenter[0] + 1.2*radar.fradius;
  87.   hud.shields_max[0] = hud.shields_min[0] + 0.2*radar.fradius;
  88.   hud.shields_min[1] = hud.throt_min[1];
  89.   hud.shields_max[1] = hud.throt_max[1];
  90.  
  91.   /* Target shields */
  92.   hud.targshields_min[0] = radar.fcenter[0] + 1.5*radar.fradius;
  93.   hud.targshields_max[0] = hud.targshields_min[0] + 0.2*radar.fradius;
  94.   hud.targshields_min[1] = hud.throt_min[1];
  95.   hud.targshields_max[1] = hud.throt_max[1];
  96.  
  97.   lock.target = -1;
  98.   lock.type = LOCK_ENEMY;
  99. }
  100.  
  101. static GLubyte center_cursor[8] =
  102. {
  103.   0x10, 0x10, 0x00, 0xc6, 0x00, 0x10, 0x10, 0x00 }
  104. ;
  105.  
  106. void Hud()
  107. /*
  108.  *  Show the Heads Up Display
  109.  */
  110. {
  111.   char buf[256];
  112.  
  113.   /* Set up viewing matrix */
  114.   glMatrixMode (GL_MODELVIEW);
  115.   glPushMatrix();
  116.   glLoadIdentity();
  117.  
  118.   glMatrixMode (GL_PROJECTION);
  119.   glPushMatrix();
  120.   glLoadIdentity();
  121.  
  122.   glOrtho (0.0, ((double)ScreenWidth), 0.0, ((double)ScreenHeight), -1.0, 1.0);
  123.  
  124.   /* Disable three-D stuff */
  125.   glDisable (GL_DEPTH_TEST);
  126.   glDisable (GL_CULL_FACE);
  127.   glDisable (GL_LIGHTING);
  128.  
  129.   /* Try displaying a crosshair */
  130.   if (drawhud)
  131.   {
  132.     glColor3d (0.8, 0.8, 0.8);
  133.     glRasterPos2i (ScreenWidth/2, ScreenHeight/2);
  134.     glBitmap (8, 8, 3.0, 5.0, 0.0, 0.0, center_cursor);
  135.  
  136.     /* Display the radar */
  137.     Radar();
  138.  
  139.     /* Display the throttle */
  140.     Throttle();
  141.  
  142.     /* Velocity */
  143.     PlayerVel();
  144.  
  145.     /* Show target stuff */
  146.     TargetStuff();
  147.  
  148.     /* Current weapon */
  149.     ShowWeapon();
  150.  
  151.     /* Waypoint stuff */
  152.     WaypointStuff();
  153.  
  154.     /* Shields display */
  155.     Shields();
  156.  
  157.     /* Print the performance monitor */
  158.     if (showfps)
  159.     {
  160.       glColor3d (1.0, 1.0, 1.0);
  161.       glRasterPos2i (1, 5);
  162.  
  163.       sprintf (buf, "fps: %2.1f  ", fps);
  164.       Print (GLUT_BITMAP_HELVETICA_10, buf); 
  165.       
  166.       /* Show bandwidth */ 
  167.       if (am_client || am_server) 
  168.       {
  169.         if (recv_bps > 0.0) 
  170.         {
  171.           glColor3d (1.0, 0.0, 0.0); 
  172.           glRasterPos2i (1, 15); 
  173.           sprintf (buf, "R:%4.0lf  ", recv_bps); 
  174.           Print (GLUT_BITMAP_HELVETICA_10, buf); 
  175.         }
  176.         
  177.         if (xmit_bps > 0.0) 
  178.         {
  179.           glColor3d (0.0, 1.0, 0.0); 
  180.           glRasterPos2i (1, 25); 
  181.           sprintf (buf, "S:%4.0lf  ", xmit_bps); 
  182.           Print (GLUT_BITMAP_HELVETICA_10, buf); 
  183.         }
  184.       }
  185.     }
  186.   }
  187.  
  188.   /* Display the message console */
  189.   DisplayConsole();
  190.  
  191.   /* Display ceter-of-screen messages */
  192.   DrawMessage();
  193.  
  194.   glMatrixMode (GL_PROJECTION);
  195.   glPopMatrix();
  196.  
  197.   glMatrixMode (GL_MODELVIEW);
  198.   glPopMatrix();
  199.  
  200.   /* Draw various on-screen cursors */
  201.   if (drawhud)
  202.   {
  203.     /* The locked target */
  204.     DrawLock();
  205.  
  206.     /* Motion cursors */
  207.     DrawMotionCursors();
  208.  
  209.     /* Waypoint cursor */
  210.     DrawWaypoint();
  211.   }
  212.  
  213.   /* Re-enable three-D stuff */
  214.   glEnable (GL_DEPTH_TEST);
  215.   glEnable (GL_CULL_FACE);
  216.   glEnable (GL_LIGHTING);
  217. }
  218.  
  219. void RadarCoords (double *v, double *x, double *y)
  220. /*
  221.  *  Compute the two-D radar coordinates of an object
  222.  */
  223. {
  224.   double v2[3], v3[3], v4[3], t, r;
  225.  
  226.   /* Compute coords of object relative to player */
  227.   Vsub (v2, v, player.pos);
  228.  
  229.   /* Normalize that */
  230.   Normalize (v2);
  231.  
  232.   /* Distance of blip from center of radar is cosine of angle
  233.     between view direction and direction to object */
  234.   radarR = Dotp (player.view, v2);
  235.  
  236.   /* Find magnitude of projection of v2 onto view vector */
  237.   t = Dotp (v2, player.view);
  238.  
  239.   /* Determine projection of object on plane perpendicular
  240.     to viewing plane */
  241.   Vmul (v3, player.view, -t);
  242.   Vadd (v4, v3, v2);
  243.  
  244.   /* Handle special case of null v4, meaning object is on
  245.     line of sight */
  246.   if (0.0 == Mag2(v4))
  247.   {
  248.     radarCOS = 1.0;
  249.     radarSIN = 0.0;
  250.     return;
  251.   }
  252.  
  253.   /* Else normalize v4 */
  254.   Normalize (v4);
  255.  
  256.   /* v4 is now a vector from player's viewpoint to projection
  257.     of object on the player's plane.  Compute angle from player's
  258.     up vector to object */
  259.   radarCOS = Dotp (player.up, v4);
  260.   radarSIN = Dotp (player.right, v4);
  261.  
  262.   /* Convert to cartesian */
  263.   r = (1.0 - radarR) / 2.0;
  264.   *x = radar.fcenter[0] + radar.fradius * -r * radarSIN;
  265.   *y = radar.fcenter[1] + radar.fradius * r * radarCOS;
  266. }
  267.  
  268. void Radar()
  269. /*
  270.  *  Display the Wing Commander-like radar
  271.  */
  272. {
  273.   /* Draw the circle around the radar */
  274.   DrawRadarCircle();
  275.  
  276.   /* Draw the objects */
  277.   RadarPlanets();
  278.   RadarTargets();
  279.   RadarMissiles();
  280.   RadarWaypoint();
  281. }
  282.  
  283. void InitRadar()
  284. /*
  285.  *  Set up the radar coordinates
  286.  */
  287. {
  288.   radar.fcenter[0] = ScreenWidth / 2.0;
  289.   radar.center[0] = (int) radar.fcenter[0];
  290.  
  291.   radar.fcenter[1] = ScreenHeight / 8.0;
  292.   radar.center[1] = (int) radar.fcenter[1];
  293.  
  294.   radar.fradius = ScreenHeight / 8.0 - 10.0;
  295.   radar.radius = (int) radar.fradius;
  296. }
  297.  
  298. void DrawRadarCircle()
  299. {
  300.   glCallList (radar.list);
  301. }
  302.  
  303. void MakeRadarCircleList()
  304. /*
  305.  *  Define the radar circle list
  306.  */
  307. {
  308.   double x, y, theta;
  309.  
  310.   /* Delete the list if it already exists */
  311.   if (glIsList (radar.list)) glDeleteLists (radar.list, 1);
  312.  
  313.   radar.list = glGenLists (1);
  314.   glNewList (radar.list, GL_COMPILE);
  315.  
  316.   glEnable (GL_POLYGON_STIPPLE);
  317.   glPolygonStipple (throt_stipple);
  318.  
  319.   /* Fill in radar circle */
  320.   glColor3d (0.0, 0.0, 0.1);
  321.   glBegin (GL_POLYGON);
  322.   for (theta=0.0; theta<6.29; theta+=0.314)
  323.   {
  324.     y = (double) sin ((double) theta);
  325.     x = (double) cos ((double) theta);
  326.  
  327.     x = radar.fcenter[0] + x * radar.fradius;
  328.     y = radar.fcenter[1] + y * radar.fradius;
  329.  
  330.     glVertex2d (x, y);
  331.   }
  332.   glEnd();
  333.  
  334.   /* Draw yellow border */
  335.   glColor3d (0.3, 0.3, 0.0);
  336.   glBegin (GL_LINE_LOOP);
  337.   for (theta=0.0; theta<6.29; theta+=0.314)
  338.   {
  339.     y = (double) sin ((double) theta);
  340.     x = (double) cos ((double) theta);
  341.  
  342.     x = radar.fcenter[0] + x * radar.fradius;
  343.     y = radar.fcenter[1] + y * radar.fradius;
  344.  
  345.     glVertex2d (x, y);
  346.   }
  347.   glEnd();
  348.  
  349.   /* Draw inner circle */
  350.   glBegin (GL_LINE_LOOP);
  351.   for (theta=0.0; theta<6.29; theta+=0.314)
  352.   {
  353.     y = (double) sin ((double) theta);
  354.     x = (double) cos ((double) theta);
  355.  
  356.     x = radar.fcenter[0] + x * radar.fradius / 2.0;
  357.     y = radar.fcenter[1] + y * radar.fradius / 2.0;
  358.  
  359.     glVertex2d (x, y);
  360.   }
  361.   glEnd();
  362.  
  363.   /* Draw connecting lines */
  364.   glBegin (GL_LINES);
  365.   x = radar.fcenter[0] + 0.7071 * radar.fradius;
  366.   y = radar.fcenter[1] + 0.7071 * radar.fradius;
  367.   glVertex2d (x, y);
  368.   x = radar.fcenter[0] + 0.7071 * radar.fradius / 2.0;
  369.   y = radar.fcenter[1] + 0.7071 * radar.fradius / 2.0;
  370.   glVertex2d (x, y);
  371.  
  372.   glBegin (GL_LINES);
  373.   x = radar.fcenter[0] - 0.7071 * radar.fradius;
  374.   y = radar.fcenter[1] + 0.7071 * radar.fradius;
  375.   glVertex2d (x, y);
  376.   x = radar.fcenter[0] - 0.7071 * radar.fradius / 2.0;
  377.   y = radar.fcenter[1] + 0.7071 * radar.fradius / 2.0;
  378.   glVertex2d (x, y);
  379.  
  380.   glBegin (GL_LINES);
  381.   x = radar.fcenter[0] - 0.7071 * radar.fradius;
  382.   y = radar.fcenter[1] - 0.7071 * radar.fradius;
  383.   glVertex2d (x, y);
  384.   x = radar.fcenter[0] - 0.7071 * radar.fradius / 2.0;
  385.   y = radar.fcenter[1] - 0.7071 * radar.fradius / 2.0;
  386.   glVertex2d (x, y);
  387.  
  388.   glBegin (GL_LINES);
  389.   x = radar.fcenter[0] + 0.7071 * radar.fradius;
  390.   y = radar.fcenter[1] - 0.7071 * radar.fradius;
  391.   glVertex2d (x, y);
  392.   x = radar.fcenter[0] + 0.7071 * radar.fradius / 2.0;
  393.   y = radar.fcenter[1] - 0.7071 * radar.fradius / 2.0;
  394.   glVertex2d (x, y);
  395.  
  396.   glEnd();
  397.  
  398.   glDisable (GL_POLYGON_STIPPLE);
  399.  
  400.   glEndList();
  401. }
  402.  
  403. void RadarPlanets()
  404. /*
  405.  *  Draw the planets on the radar
  406.  */
  407. {
  408.   int p;
  409.   double x, y;
  410.  
  411.   for (p=0; p<NPLANETS; p++)
  412.   {
  413.     if (!planet[p].hidden)
  414.     {
  415.       if ((!planet[p].is_moon) || (planet[p].range2 < (1000.0 * 1000.0)))
  416.       {
  417.         /* Convert to radar coords */
  418.         RadarCoords (planet[p].pos, &x, &y);
  419.  
  420.         /* Draw it */
  421.         if ( (lock.type == LOCK_PLANET) &&
  422.         (lock.target == p) )
  423.         {
  424.           glPointSize (4.0);
  425.         }
  426.         else
  427.         {
  428.           glPointSize (3.0);
  429.         }
  430.         glBegin (GL_POINTS);
  431.         if (planet[p].is_moon)
  432.         glColor3d (0.0, 1.0, 1.0);
  433.         else
  434.         glColor3d (0.0, 0.0, 1.0);
  435.         glVertex2d (x, y);
  436.         glEnd();
  437.       }
  438.     }
  439.   }
  440. }
  441.  
  442. void RadarTargets()
  443. /*
  444.  *  Draw the targets on the radar
  445.  */
  446. {
  447.   double x, y;
  448.   int i;
  449.  
  450.   /* glColor3d (0.9, 0.0, 0.0); */
  451.  
  452.   for (i=0; i<NTARGETS; i++)
  453.   {
  454.     /* Is this a network game and this target is us? */
  455.     /*  if (am_client && (i == client[clientme.client].target)) continue; */
  456.     if (am_server && (i == client[server.client].target)) continue;
  457.  
  458.     if ( (target[i].age > 0.0) &&
  459.     (target[i].range2 < TARG_MAXRANGE2) &&
  460.     (!target[i].hidden) &&
  461.     (!target[i].invisible) )
  462.     {
  463.       /* Convert to radar coords */
  464.       RadarCoords (target[i].pos, &x, &y);
  465.  
  466.       /* Select color */
  467.       if (target[i].friendly)
  468.       glColor3d (0.0, 0.9, 0.0);
  469.       else
  470.       glColor3d (0.9, 0.0, 0.0);
  471.  
  472.       /* Draw locked target bigger */
  473.       if (i == lock.target)
  474.       {
  475.         glPointSize (3.0);
  476.         glBegin (GL_POINTS);
  477.         glVertex2d (x, y);
  478.       }
  479.       else
  480.       {
  481.         /* Just Draw it */
  482.         glPointSize (2.0);
  483.         glBegin (GL_POINTS);
  484.         glVertex2d (x, y);
  485.       }
  486.  
  487.       glEnd();
  488.     }
  489.   }
  490.   glEnd();
  491. }
  492.  
  493. void RadarMissiles()
  494. /*
  495.  *  Draw the missiles on the radar
  496.  */
  497. {
  498.   double x, y;
  499.   int i;
  500.  
  501.   glPointSize (1.0);
  502.   glBegin (GL_POINTS);
  503.  
  504.   /* Missiles are yellow */
  505.   glColor3d (1.0, 1.0, 0.0);
  506.  
  507.   for (i=0; i<NMSLS; i++)
  508.   {
  509.     if (msl[i].age > 0.0)
  510.     {
  511.       /* Convert to radar coords */
  512.       RadarCoords (msl[i].pos, &x, &y);
  513.  
  514.       /* Draw it */
  515.       glVertex2d (x, y);
  516.     }
  517.   }
  518.   glEnd();
  519. }
  520.  
  521. void RadarWaypoint()
  522. /*
  523.  *  Draw the current waypoint
  524.  */
  525. {
  526.   double x, y;
  527.   int w;
  528.  
  529.   if ((-1) == (w = player.waypoint)) return;
  530.  
  531.   glPointSize (2.0);
  532.   glBegin (GL_POINTS);
  533.   glColor3d (1.0, 1.0, 1.0);
  534.   RadarCoords (waypoint[w].pos, &x, &y);
  535.   glVertex2d (x, y);
  536.   glEnd();
  537. }
  538.  
  539. void LockNearest()
  540. /*
  541.  *  Lock onto the nearest target
  542.  */
  543. {
  544.   int t, ok;
  545.   double d;
  546.  
  547.   d = -1.0;
  548.  
  549.   if (lock.type == LOCK_ENEMY)
  550.   {
  551.     for (t=0; t<NTARGETS; t++)
  552.     {
  553.       if (am_client || am_server) 
  554.       {
  555.         /* Can lock distant targets in network games */ 
  556.         ok = ( (target[t].age > 0.0) && 
  557.         (!target[t].hidden) && 
  558.         (!target[t].invisible) && 
  559.         (!target[t].friendly) ); 
  560.       }
  561.       else 
  562.       {
  563.         ok = ( (target[t].age > 0.0) && 
  564.         (!target[t].hidden) && 
  565.         (!target[t].invisible) && 
  566.         (!target[t].friendly) && 
  567.         (target[t].range2 < TARG_MAXRANGE2) ); 
  568.       }
  569.       
  570.       if (ok)
  571.       {
  572.         if ( (d < 0.0) || (target[t].range2 < d) )
  573.         {
  574.           d = target[t].range2;
  575.           lock.target = t;
  576.         }
  577.       }
  578.     }
  579.   }
  580.   else if (lock.type == LOCK_FRIENDLY)
  581.   {
  582.     for (t=0; t<NTARGETS; t++)
  583.     {
  584.       if ( (target[t].age > 0.0) &&
  585.       (!target[t].hidden) &&
  586.       (!target[t].invisible) &&
  587.       (target[t].range2 < TARG_MAXRANGE2) &&
  588.       (target[t].friendly) )
  589.       {
  590.         if ( (d < 0.0) || (target[t].range2 < d) )
  591.         {
  592.           d = target[t].range2;
  593.           lock.target = t;
  594.         }
  595.       }
  596.     }
  597.   }
  598.   else if (lock.type == LOCK_PLANET)
  599.   {
  600.     for (t=0; t<NPLANETS; t++)
  601.     {
  602.       if (!planet[t].hidden)
  603.       {
  604.         if ( (d < 0.0) || (planet[t].absrange2 < d) )
  605.         {
  606.           d = planet[t].absrange2;
  607.           lock.target = t;
  608.         }
  609.       }
  610.     }
  611.   }
  612. }
  613.  
  614. void LockNext()
  615. /*
  616.  *  Lock onto next target
  617.  */
  618. {
  619.   int t, tt, old, ok;
  620.  
  621.   old = lock.target;
  622.  
  623.   /* Check if we're not locked yet */
  624.   if (lock.target == -1) lock.target = 0;
  625.  
  626.   if (lock.type == LOCK_ENEMY)
  627.   {
  628.     for (t=lock.target; t<lock.target+NTARGETS; t++)
  629.     {
  630.       tt = t % NTARGETS;
  631.       
  632.       if (am_client || am_server) 
  633.       {
  634.         /* Can lock distant targets in network games */ 
  635.         ok = ( (target[tt].age > 0.0) && 
  636.         (!target[tt].hidden) && 
  637.         (!target[tt].invisible) && 
  638.         (!target[tt].friendly) && 
  639.         (tt != old) ); 
  640.       }
  641.       else 
  642.       {
  643.         ok = ( (target[tt].age > 0.0) &&
  644.         (!target[tt].hidden) &&
  645.         (!target[tt].invisible) &&
  646.         (!target[tt].friendly) &&
  647.         (target[tt].range2 < TARG_MAXRANGE2) &&
  648.         (tt != old) ); 
  649.       }
  650.       
  651.       if (ok)
  652.       {
  653.         lock.target = tt;
  654.         return;
  655.       }
  656.     }
  657.   }
  658.   else if (lock.type == LOCK_FRIENDLY)
  659.   {
  660.     for (t=lock.target; t<lock.target+NTARGETS; t++)
  661.     {
  662.       tt = t % NTARGETS;
  663.  
  664.       if ( (target[tt].age > 0.0) &&
  665.       (!target[tt].hidden) &&
  666.       (!target[tt].invisible) &&
  667.       (target[tt].friendly) &&
  668.       (target[tt].range2 < TARG_MAXRANGE2) &&
  669.       (tt != old) )
  670.       {
  671.         lock.target = tt;
  672.         return;
  673.       }
  674.     }
  675.   }
  676.   else if (lock.type == LOCK_PLANET)
  677.   {
  678.     do
  679.     {
  680.       lock.target = (lock.target + 1) % NPLANETS;
  681.     }
  682.     while ( (planet[lock.target].is_moon &&
  683.     (planet[lock.target].range2 > (5000.0*5000.0)) ) ||
  684.     planet[lock.target].hidden);
  685.     return;
  686.   }
  687.  
  688.   /* Nothing new to lock onto */
  689.   lock.target = old;
  690. }
  691.  
  692. void LockPrev()
  693. /*
  694.  *  Lock onto previous target
  695.  */
  696. {
  697.   int t, tt, old, ok;
  698.  
  699.   old = lock.target;
  700.  
  701.   /* Check if we're not locked yet */
  702.   if (lock.target == -1) lock.target = 0;
  703.  
  704.   if (lock.type == LOCK_ENEMY)
  705.   {
  706.     for (t=lock.target+NTARGETS; t>lock.target; t--)
  707.     {
  708.       tt = t % NTARGETS;
  709.       
  710.       if (am_client || am_server) 
  711.       {
  712.         ok = ( (target[tt].age > 0.0) && 
  713.         (!target[tt].hidden) && 
  714.         (!target[tt].invisible) && 
  715.         (!target[tt].friendly) && 
  716.         (tt != old) ); 
  717.       }
  718.       else 
  719.       {
  720.         ok = ( (target[tt].age > 0.0) && 
  721.         (!target[tt].hidden) && 
  722.         (!target[tt].invisible) && 
  723.         (!target[tt].friendly) && 
  724.         (target[tt].range2 < TARG_MAXRANGE2) && 
  725.         (tt != old) ); 
  726.       }
  727.       
  728.       if (ok) 
  729.       {
  730.         lock.target = tt;
  731.         return;
  732.       }
  733.     }
  734.   }
  735.   else if (lock.type == LOCK_FRIENDLY)
  736.   {
  737.     for (t=lock.target+NTARGETS; t>lock.target; t--)
  738.     {
  739.       tt = t % NTARGETS;
  740.  
  741.       if ( (target[tt].age > 0.0) &&
  742.       (!target[tt].hidden) &&
  743.       (!target[tt].invisible) &&
  744.       (target[tt].friendly) &&
  745.       (target[tt].range2 < TARG_MAXRANGE2) &&
  746.       (tt != old) )
  747.       {
  748.         lock.target = tt;
  749.         return;
  750.       }
  751.     }
  752.   }
  753.   else if (lock.type == LOCK_PLANET)
  754.   {
  755.     do
  756.     {
  757.       lock.target = (lock.target + NPLANETS - 1) % NPLANETS;
  758.     }
  759.     while ( (planet[lock.target].is_moon &&
  760.     (planet[lock.target].range2 > (5000.0*5000.0)) ) ||
  761.     planet[lock.target].hidden);
  762.     return;
  763.   }
  764.  
  765.   /* Nothing new to lock onto */
  766.   lock.target = old;
  767. }
  768.  
  769. void CheckLock()
  770. /*
  771.  *  Sanity checks on the locked target
  772.  */
  773. {
  774.   int l;
  775.  
  776.   l = lock.target;
  777.  
  778.   if (lock.type == LOCK_PLANET)
  779.   {
  780.     /* Can't lock hidden planets */
  781.     if (planet[l].hidden) lock.target = -1;
  782.   }
  783.  
  784.   if (lock.type == LOCK_FRIENDLY)
  785.   {
  786.     if (!target[l].friendly) lock.type = LOCK_ENEMY;
  787.     if (target[l].hidden) lock.target = -1;
  788.     if (target[l].invisible) lock.target = -1;
  789.     if (target[l].age == 0.0) lock.target = -1;
  790.     if (target[l].range2 > TARG_MAXRANGE2) lock.target = -1;
  791.   }
  792.  
  793.   if (lock.type == LOCK_ENEMY)
  794.   {
  795.     if (target[l].friendly) lock.type = LOCK_FRIENDLY;
  796.     if (target[l].hidden) lock.target = -1;
  797.     if (target[l].invisible) lock.target = -1;
  798.     if (target[l].age == 0.0) lock.target = -1; 
  799.     
  800.     if (!am_client && !am_server) 
  801.     {
  802.       if (target[l].range2 > TARG_MAXRANGE2) lock.target = -1; 
  803.     }
  804.   }
  805. }
  806.  
  807. static GLubyte lock_cursor[32] =
  808. {
  809.   0xff, 0xff, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
  810.   0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
  811.   0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
  812.   0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff }
  813. ;
  814.  
  815. static GLubyte aim_cursor[8] =
  816. {
  817.   0x81, 0x42, 0x24, 0x00, 0x00, 0x24, 0x42, 0x81 }
  818. ;
  819.  
  820. static GLubyte motion_cursor[8] =
  821. {
  822.   0x18, 0x24, 0x42, 0x81, 0x81, 0x42, 0x24, 0x18 }
  823. ;
  824.  
  825. static GLubyte waypoint_cursor[8] =
  826. {
  827.   0x3c, 0x00, 0x81, 0x81, 0x81, 0x81, 0x00, 0x3c }
  828. ;
  829.  
  830. void DrawLock()
  831. /*
  832.  *  Draw the lock cursor
  833.  */
  834. {
  835.   char v;
  836.   double vtarg[3], v1[3];
  837.  
  838.   /* Don't bother if we're not locked */
  839.   if (lock.target == -1) return;
  840.  
  841.   /* Planets are special */
  842.   if (lock.type == LOCK_PLANET)
  843.   {
  844.     DrawPlanetLock();
  845.     return;
  846.   }
  847.  
  848.   /* Or if out of range */ 
  849.   if (!am_client && !am_server) 
  850.   {
  851.     if (target[lock.target].range2 > TARG_MAXRANGE2) return; 
  852.   }
  853.  
  854.   /* Select color */
  855.   if (target[lock.target].friendly)
  856.   glColor3d (0.0, 0.9, 0.0);
  857.   else
  858.   glColor3d (0.9, 0.0, 0.0);
  859.  
  860.   /* Set raster position, check if valid */
  861.   Vsub (v1, target[lock.target].pos, player.pos);
  862.   glRasterPos3dv (v1);
  863.   glGetBooleanv (GL_CURRENT_RASTER_POSITION_VALID, &v);
  864.   if (v)
  865.   {
  866.     /* Draw cursor */
  867.     glBitmap (16, 16, 8.0, 8.0, 0.0, 0.0, lock_cursor);
  868.   }
  869.  
  870.   /* Try to draw the aiming cursor */
  871.   if (target[lock.target].range2 > weapon[player.weapon].range2) return; 
  872.   if (!target[lock.target].friendly)
  873.   {
  874.     if (!am_client && !am_server) 
  875.     {
  876.       Vmul (v1, player.up, -0.01);
  877.       Vadd (v1, v1, player.pos); 
  878.     }
  879.     else 
  880.     {
  881.       Vset (v1, player.pos); 
  882.     }
  883.     if (Aim (vtarg, v1, player.vel,
  884.     target[lock.target].pos, target[lock.target].vel,
  885.     weapon[player.weapon].speed) )
  886.     {
  887.       glColor3d (1.0, 1.0, 0.0);
  888.       Vsub (vtarg, vtarg, player.pos);
  889.       glRasterPos3dv (vtarg);
  890.       glGetBooleanv (GL_CURRENT_RASTER_POSITION_VALID, &v);
  891.       if (v)
  892.       {
  893.         glBitmap (8, 8, 4.0, 4.0, 0.0, 0.0, aim_cursor);
  894.       }
  895.     }
  896.   }
  897. }
  898.  
  899. void DrawPlanetLock()
  900. {
  901.   int p;
  902.   char v;
  903.   double v1[3];
  904.  
  905.   p = lock.target;
  906.  
  907.   if (planet[p].is_moon)
  908.   glColor3d (0.0, 1.0, 1.0);
  909.   else
  910.   glColor3d (0.0, 0.0, 1.0);
  911.  
  912.   /* Set raster postition, check if valid */
  913.   Vsub (v1, planet[p].pos, player.pos);
  914.   glRasterPos3dv (v1);
  915.   glGetBooleanv (GL_CURRENT_RASTER_POSITION_VALID, &v);
  916.   if (v)
  917.   {
  918.     /* Draw cursor */
  919.     glBitmap (16, 16, 8.0, 8.0, 0.0, 0.0, lock_cursor);
  920.   }
  921. }
  922.  
  923. void DrawWaypoint()
  924. {
  925.   int w;
  926.   char v;
  927.   double v1[3];
  928.  
  929.   w = player.waypoint;
  930.   if (w == (-1)) return;
  931.  
  932.   glColor3d (0.8, 0.8, 1.8);
  933.  
  934.   /* Set raster postition, check if valid */
  935.   Vsub (v1, waypoint[w].pos, player.pos);
  936.   glRasterPos3dv (v1);
  937.   glGetBooleanv (GL_CURRENT_RASTER_POSITION_VALID, &v);
  938.   if (v)
  939.   {
  940.     /* Draw cursor */
  941.     glBitmap (8, 8, 3.0, 4.0, 0.0, 0.0, waypoint_cursor);
  942.   }
  943. }
  944.  
  945. void DrawMotionCursors()
  946. /*
  947.  *  Show forward and reverse motion
  948.  */
  949. {
  950.   double vn[3];
  951.   char v;
  952.  
  953.   /* Not in arcade mode */
  954.   if (player.flightmodel == FLIGHT_ARCADE) return;
  955.  
  956.   /* Not unless we're moving */
  957.   if ( (0.0 == player.vel[0]) &&
  958.   (0.0 == player.vel[1]) &&
  959.   (0.0 == player.vel[2]) ) return;
  960.  
  961.   /* Forward cursor */
  962.   Vset (vn, player.vel);
  963.   Normalize (vn);
  964.  
  965.   glColor3d (0.0, 0.8, 0.0);
  966.   glRasterPos3dv (vn);
  967.   glGetBooleanv (GL_CURRENT_RASTER_POSITION_VALID, &v);
  968.   if (v)
  969.   {
  970.     /* Draw cursor */
  971.     glBitmap (8, 8, 4.0, 4.0, 0.0, 0.0, motion_cursor);
  972.   }
  973.  
  974.   /* Reverse cursor */
  975.   Vmul (vn, vn, -1.0);
  976.   
  977.   glColor3d (0.8, 0.0, 0.0);
  978.   glRasterPos3dv (vn);
  979.   glGetBooleanv (GL_CURRENT_RASTER_POSITION_VALID, &v);
  980.   if (v)
  981.   {
  982.     /* Draw cursor */
  983.     glBitmap (8, 8, 4.0, 4.0, 0.0, 0.0, motion_cursor);
  984.   }
  985. }
  986.  
  987. int Aim (double *vtarg, double *pos0, double *vel0, double *pos1, double *vel1, double vel)
  988. /*
  989.  *  Something at position pos0, with velocity vector vel0,
  990.  *  wants to shoot a missile with velocity "vel" at a target
  991.  *  at position pos1, moving with vector vel1.
  992.  *
  993.  *  Coord of place to shoot will be in vtarg, unless there is
  994.  *  no solution, in which case we return FALSE.
  995.  */
  996. {
  997.   double va[3], vb[3], A, B, C, D, t, t1, t2, rootD;
  998.  
  999.   /* va is position of target wrt shooter */
  1000.   Vsub (va, pos1, pos0);
  1001.  
  1002.   /* vb is relative velocity of target */
  1003.   Vsub (vb, vel1, vel0);
  1004.  
  1005.   /* If there's a solution, then there exists some t such
  1006.     that target postion (va) plus t times its velocity (vb)
  1007.     is as far away from shooter (origin) as a missile can
  1008.     travel in time t (t*vel).  If you work it out you get
  1009.     a pretty simple quadratic equation. */
  1010.  
  1011.   /* Set up coefficients of quadratic equation */
  1012.   A = vb[0]*vb[0] + vb[1]*vb[1] + vb[2]*vb[2] - vel*vel;
  1013.   B = 2.0*va[0]*vb[0] + 2.0*va[1]*vb[1] + 2.0*va[2]*vb[2];
  1014.   C = va[0]*va[0] + va[1]*va[1] + va[2]*va[2];
  1015.  
  1016.   /* This is the kind of stuff you thought you'd never
  1017.     use in real life, isn't it? */
  1018.  
  1019.   /* A == 0 is special case */
  1020.   if (A == 0.0)
  1021.   {
  1022.     /* A==0 && B==0 implies no solution */
  1023.     if (B == 0.0) return (0);
  1024.  
  1025.     /* Simple solution */
  1026.     t = (-C / B);
  1027.  
  1028.     /* Can't shoot missiles backwards */
  1029.     if (t < 0.0) return (0);
  1030.   }
  1031.   else
  1032.   {
  1033.     /* More complicated cases */
  1034.     /* Compute discriminant */
  1035.     D = B*B - 4.0*A*C;
  1036.  
  1037.     /* D < 0 implies no solution */
  1038.     if (D < 0.0) return (0);
  1039.  
  1040.     /* D == 0 implies one solution */
  1041.     if (D == 0.0)
  1042.     {
  1043.       t = -B / (2.0 * A);
  1044.       if (t <= 0.0) return (0);
  1045.     }
  1046.     else
  1047.     {
  1048.       /* Two solutions */
  1049.       rootD = sqrt (D);
  1050.       t1 = (-B + rootD) / (2.0 * A);
  1051.       t2 = (-B - rootD) / (2.0 * A);
  1052.  
  1053.       /* We need a non-negative solution */
  1054.       if ( (t1 < 0.0) && (t2 < 0.0) ) return (0);
  1055.  
  1056.       if (t1 < 0.0)
  1057.       t = t2;
  1058.       else if (t2 < 0.0)
  1059.       t = t1;
  1060.       else
  1061.       {
  1062.         /* Both non-negative, choose lesser
  1063.        (closer to target) */
  1064.         if (t1 < t2)
  1065.         t = t1;
  1066.         else
  1067.         t = t2;
  1068.       }
  1069.     }
  1070.   }
  1071.  
  1072.   /* Whew!  We have a solution in t now. */
  1073.   Vmul (vtarg, vb, t);
  1074.   Vadd (vtarg, vtarg, va);
  1075.   Vadd (vtarg, vtarg, pos0);
  1076.  
  1077.   return (1);
  1078. }
  1079.  
  1080. void ArcadeThrottle()
  1081. /*
  1082.  *  Draw the throttle for arcade mode
  1083.  */
  1084. {
  1085.   double y;
  1086.  
  1087.   glEnable (GL_POLYGON_STIPPLE);
  1088.   glPolygonStipple (throt_stipple);
  1089.  
  1090.   /* First draw unshaded background */
  1091.   glColor3f (0.0, 0.25, 0.0);
  1092.   glBegin (GL_QUAD_STRIP);
  1093.   glVertex2d (hud.throt_min[0], hud.throt_min[1]);
  1094.   glVertex2d (hud.throt_max[0], hud.throt_min[1]);
  1095.   glVertex2d (hud.throt_min[0], hud.throt_max[1]);
  1096.   glVertex2d (hud.throt_max[0], hud.throt_max[1]);
  1097.   glEnd();
  1098.  
  1099.   if (player.throttle > MAX_THROTTLE)
  1100.   {
  1101.     y = hud.throt_min[1] + (player.throttle / MAX_WARP_THROTTLE) *
  1102.     (hud.throt_max[1] - hud.throt_min[1]);
  1103.   }
  1104.   else
  1105.   {
  1106.     y = hud.throt_min[1] + (player.throttle / MAX_THROTTLE) *
  1107.     (hud.throt_max[1] - hud.throt_min[1]);
  1108.   }
  1109.  
  1110.   glColor3f (0.0, 0.75, 0.0);
  1111.   glBegin (GL_QUAD_STRIP);
  1112.   glVertex2d (hud.throt_min[0], hud.throt_min[1]);
  1113.   glVertex2d (hud.throt_max[0], hud.throt_min[1]);
  1114.   glVertex2d (hud.throt_min[0], y);
  1115.   glVertex2d (hud.throt_max[0], y);
  1116.   glEnd();
  1117.  
  1118.   glDisable (GL_POLYGON_STIPPLE);
  1119.  
  1120.   /* If travelling at warp speed, put a border around throttle */
  1121.   if (player.throttle > MAX_THROTTLE)
  1122.   {
  1123.     glColor3f (0.5, 0.5, 0.0);
  1124.     glBegin (GL_LINE_LOOP);
  1125.     glVertex2d (hud.throt_min[0], hud.throt_min[1]);
  1126.     glVertex2d (hud.throt_max[0], hud.throt_min[1]);
  1127.     glVertex2d (hud.throt_max[0], hud.throt_max[1]);
  1128.     glVertex2d (hud.throt_min[0], hud.throt_max[1]);
  1129.     glEnd();
  1130.   }
  1131. }
  1132.  
  1133. void Throttle()
  1134. /*
  1135.  *  Draw the throttle
  1136.  */
  1137. {
  1138.   double y;
  1139.  
  1140.   /* Arcade mode is special */
  1141.   if (player.flightmodel == FLIGHT_ARCADE)
  1142.   {
  1143.     ArcadeThrottle();
  1144.     return;
  1145.   }
  1146.   
  1147.   glEnable (GL_POLYGON_STIPPLE);
  1148.   glPolygonStipple (throt_stipple);
  1149.  
  1150.   /* First draw unshaded background */
  1151.   glColor3f (0.25, 0.0, 0.0);
  1152.   glBegin (GL_QUAD_STRIP);
  1153.   glVertex2d (hud.throt_min[0], hud.throt_min[1]);
  1154.   glVertex2d (hud.throt_max[0], hud.throt_min[1]);
  1155.   glVertex2d (hud.throt_min[0], hud.throt_mid[1]);
  1156.   glVertex2d (hud.throt_max[0], hud.throt_mid[1]);
  1157.   glEnd();
  1158.   glColor3f (0.0, 0.25, 0.0);
  1159.   glBegin (GL_QUAD_STRIP);
  1160.   glVertex2d (hud.throt_min[0], hud.throt_mid[1]);
  1161.   glVertex2d (hud.throt_max[0], hud.throt_mid[1]);
  1162.   glVertex2d (hud.throt_min[0], hud.throt_max[1]);
  1163.   glVertex2d (hud.throt_max[0], hud.throt_max[1]);
  1164.   glEnd();
  1165.  
  1166.   /* Now show the throttle */
  1167.   if (player.move_forward > 0.0)
  1168.   {
  1169.     glColor3f (0.0, 0.75, 0.0);
  1170.     y = hud.throt_mid[1] + player.move_forward *
  1171.     (hud.throt_max[1] - hud.throt_mid[1]);
  1172.     glBegin (GL_QUAD_STRIP);
  1173.     glVertex2d (hud.throt_min[0], hud.throt_mid[1]);
  1174.     glVertex2d (hud.throt_max[0], hud.throt_mid[1]);
  1175.     glVertex2d (hud.throt_min[0], y);
  1176.     glVertex2d (hud.throt_max[0], y);
  1177.     glEnd();
  1178.   }
  1179.   else if (player.move_backward > 0.0)
  1180.   {
  1181.     glColor3f (0.75, 0.0, 0.0);
  1182.     y = hud.throt_mid[1] - player.move_backward *
  1183.     (hud.throt_mid[1] - hud.throt_min[1]);
  1184.     glBegin (GL_QUAD_STRIP);
  1185.     glVertex2d (hud.throt_min[0], hud.throt_mid[1]);
  1186.     glVertex2d (hud.throt_max[0], hud.throt_mid[1]);
  1187.     glVertex2d (hud.throt_min[0], y);
  1188.     glVertex2d (hud.throt_max[0], y);
  1189.     glEnd();
  1190.   }
  1191.  
  1192.   glDisable (GL_POLYGON_STIPPLE);
  1193.  
  1194.   /* If travelling at warp speed, put a border around throttle */
  1195.   if (warpspeed)
  1196.   {
  1197.     glColor3f (0.5, 0.5, 0.0);
  1198.     glBegin (GL_LINE_LOOP);
  1199.     glVertex2d (hud.throt_min[0], hud.throt_min[1]);
  1200.     glVertex2d (hud.throt_max[0], hud.throt_min[1]);
  1201.     glVertex2d (hud.throt_max[0], hud.throt_max[1]);
  1202.     glVertex2d (hud.throt_min[0], hud.throt_max[1]);
  1203.     glEnd();
  1204.   }
  1205. }
  1206.  
  1207. void TargetStuff()
  1208. /*
  1209.  *  Show stuff about the locked target
  1210.  */
  1211. {
  1212.   int t;
  1213.   double r;
  1214.   char buf[32];
  1215.  
  1216.   /* Planet lock is special */
  1217.   if (lock.type == LOCK_PLANET)
  1218.   {
  1219.     PlanetStuff();
  1220.     return;
  1221.   }
  1222.  
  1223.   if (-1 != (t = lock.target))
  1224.   {
  1225.     /* Bail if too far away */ 
  1226.     if (!am_client && !am_server) 
  1227.     {
  1228.       if (target[lock.target].range2 > TARG_MAXRANGE2) return; 
  1229.     }
  1230.  
  1231.     /* Target name */
  1232.     if (target[t].friendly)
  1233.     glColor3f (0.0, 0.8, 0.0);
  1234.     else
  1235.     glColor3f (0.8, 0.0, 0.0);
  1236.  
  1237.     glRasterPos2dv (hud.targ_name);
  1238.  
  1239.     /* Target range */
  1240.     r = sqrt (target[t].range2) * KM_TO_UNITS1;
  1241.     sprintf (buf, "%s:%2.0lf", target[t].name, r);
  1242.     Print (GLUT_BITMAP_HELVETICA_10, buf);
  1243.  
  1244.     /* Target shields */
  1245.     TargetShields (t);
  1246.   }
  1247. }
  1248.  
  1249. void WaypointStuff()
  1250. {
  1251.   int w;
  1252.   double r, v[3];
  1253.   char buf[32];
  1254.  
  1255.   if (player.waypoint == (-1)) return;
  1256.  
  1257.   w = player.waypoint;
  1258.   glColor3f (0.8, 0.8, 0.8);
  1259.   glRasterPos2dv (hud.waypoint);
  1260.   Vsub (v, waypoint[w].pos, player.pos);
  1261.   r = Mag (v) * KM_TO_UNITS1;
  1262.   sprintf (buf, "%d:%2.0lf", w+1, r);
  1263.   Print (GLUT_BITMAP_HELVETICA_10, buf);
  1264. }
  1265.  
  1266. void PlayerVel()
  1267. {
  1268.   double r;
  1269.   char buf[64];
  1270.  
  1271.   /* Player velocity */
  1272.   r = Mag (player.vel) * KM_TO_UNITS1;
  1273.  
  1274.   if (r == 0.0)
  1275.   glColor3f (0.0, 0.0, 0.8);
  1276.   else if (Dotp (player.view, player.vel) >= 0.0)
  1277.   glColor3f (0.0, 0.8, 0.0);
  1278.   else
  1279.   glColor3f (0.8, 0.0, 0.0);
  1280.  
  1281.   sprintf (buf, "%2.0lf", r);
  1282.   hud.vel[0] = hud.throt_min[0] - 5 - 
  1283.   glutBitmapLength (GLUT_BITMAP_HELVETICA_10, buf);
  1284.   glRasterPos2dv (hud.vel);
  1285.   Print (GLUT_BITMAP_HELVETICA_10, buf);
  1286. }
  1287.  
  1288. void PlanetStuff()
  1289. {
  1290.   int p;
  1291.   double r;
  1292.   char buf[64];
  1293.  
  1294.   if (-1 == (p = lock.target)) return;
  1295.  
  1296.   if (planet[p].is_moon)
  1297.   glColor3d (0.0, 0.8, 0.8);
  1298.   else
  1299.   glColor3d (0.0, 0.0, 0.8);
  1300.  
  1301.   glRasterPos2dv (hud.targ_name);
  1302.  
  1303.   /* Planet range */
  1304.   r = (sqrt(planet[p].absrange2) - planet[p].radius) * KM_TO_UNITS1;
  1305.   sprintf (buf, "%s:%2.0lf", planet[p].name, r);
  1306.   
  1307.   Print (GLUT_BITMAP_HELVETICA_10, buf);
  1308. }
  1309.  
  1310. void Shields()
  1311. /*
  1312.  *  Draw the shield status
  1313.  */
  1314. {
  1315.   float color[3];
  1316.   double y;
  1317.  
  1318.   glEnable (GL_POLYGON_STIPPLE);
  1319.   glPolygonStipple (throt_stipple);
  1320.  
  1321.   if (player.shields > player.maxshields*0.66)
  1322.   {
  1323.     color[0] = color[2] = 0.0;
  1324.     color[1] = 0.25;
  1325.   }
  1326.   else if (player.shields > player.maxshields*0.33)
  1327.   {
  1328.     color[0] = color[1] = 0.25;
  1329.     color[2] = 0.0;
  1330.   }
  1331.   else
  1332.   {
  1333.     color[0] = 0.25;
  1334.     color[1] = color[2] = 0.0;
  1335.   }
  1336.  
  1337.   y = hud.shields_min[1] +
  1338.   (player.shields / player.maxshields) *
  1339.   (hud.shields_max[1] - hud.shields_min[1]);
  1340.  
  1341.   /* First draw unshaded background */
  1342.   if (player.shields < player.maxshields)
  1343.   {
  1344.     glColor3fv (color);
  1345.     glBegin (GL_QUAD_STRIP);
  1346.     glVertex2d (hud.shields_min[0], y);
  1347.     glVertex2d (hud.shields_max[0], y);
  1348.     glVertex2d (hud.shields_min[0], hud.shields_max[1]);
  1349.     glVertex2d (hud.shields_max[0], hud.shields_max[1]);
  1350.     glEnd();
  1351.   }
  1352.  
  1353.   /* Now show the shields */
  1354.   color[0] *= 3.0;
  1355.   color[1] *= 3.0;
  1356.  
  1357.   glColor3fv (color);
  1358.   glBegin (GL_QUAD_STRIP);
  1359.   glVertex2d (hud.shields_min[0], hud.shields_min[1]);
  1360.   glVertex2d (hud.shields_max[0], hud.shields_min[1]);
  1361.   glVertex2d (hud.shields_min[0], y);
  1362.   glVertex2d (hud.shields_max[0], y);
  1363.   glEnd();
  1364.  
  1365.   glDisable (GL_POLYGON_STIPPLE);
  1366. }
  1367.  
  1368. void ShowWeapon()
  1369. /*
  1370.  *  Show the current weapon
  1371.  */
  1372. {
  1373.   /* Set color depending if it's ready to fire */
  1374.   if (player.msl_idle >= weapon[player.weapon].idle)
  1375.   {
  1376.     glColor3f (0.8, 0.0, 0.8);
  1377.   }
  1378.   else
  1379.   {
  1380.     glColor3f (0.5, 0.5, 0.5);
  1381.   }
  1382.   glRasterPos2dv (hud.weapon);
  1383.   Print (GLUT_BITMAP_HELVETICA_10, weapon[player.weapon].name);
  1384. }
  1385.  
  1386. void TargetShields (int t)
  1387. /*
  1388.  *  Draw the target's shield status
  1389.  */
  1390. {
  1391.   float color[3];
  1392.   double y;
  1393.  
  1394.   glEnable (GL_POLYGON_STIPPLE);
  1395.   glPolygonStipple (throt_stipple);
  1396.  
  1397.   if (target[t].shields > target[t].maxshields*0.66)
  1398.   {
  1399.     color[0] = color[2] = 0.0;
  1400.     color[1] = 0.25;
  1401.   }
  1402.   else if (target[t].shields > target[t].maxshields*0.33)
  1403.   {
  1404.     color[0] = color[1] = 0.25;
  1405.     color[2] = 0.0;
  1406.   }
  1407.   else
  1408.   {
  1409.     color[0] = 0.25;
  1410.     color[1] = color[2] = 0.0;
  1411.   }
  1412.  
  1413.   y = hud.targshields_min[1] +
  1414.   (target[t].shields / target[t].maxshields) *
  1415.   (hud.targshields_max[1] - hud.targshields_min[1]);
  1416.  
  1417.   /* First draw unshaded background */
  1418.   if (target[t].shields < target[t].maxshields)
  1419.   {
  1420.     glColor3fv (color);
  1421.     glBegin (GL_QUAD_STRIP);
  1422.     glVertex2d (hud.targshields_min[0], y);
  1423.     glVertex2d (hud.targshields_max[0], y);
  1424.     glVertex2d (hud.targshields_min[0], hud.targshields_max[1]);
  1425.     glVertex2d (hud.targshields_max[0], hud.targshields_max[1]);
  1426.     glEnd();
  1427.   }
  1428.  
  1429.   /* Now show the shields */
  1430.   color[0] *= 3.0;
  1431.   color[1] *= 3.0;
  1432.  
  1433.   glColor3fv (color);
  1434.   glBegin (GL_QUAD_STRIP);
  1435.   glVertex2d (hud.targshields_min[0], hud.targshields_min[1]);
  1436.   glVertex2d (hud.targshields_max[0], hud.targshields_min[1]);
  1437.   glVertex2d (hud.targshields_min[0], y);
  1438.   glVertex2d (hud.targshields_max[0], y);
  1439.   glEnd();
  1440.  
  1441.   glDisable (GL_POLYGON_STIPPLE);
  1442. }
  1443.